/**
 * 
 */
package com.ge.healthcare.autosc.common.commands;

import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.SocketException;
import java.util.Properties;

import org.apache.commons.net.telnet.TelnetClient;

import com.ge.healthcare.autosc.common.ASCLogger;
import com.ge.healthcare.autosc.common.ASCUtil;
import com.ge.healthcare.autosc.common.exceptions.TelnetCommandException;
import com.ge.healthcare.autosc.common.util.ASCFileHandler;
import com.ge.healthcare.autosc.common.util.ASCIOHandler;
import com.ge.healthcare.autosc.common.util.ApplicationInfo;
import com.ge.healthcare.autosc.common.util.PropertyConstants;

/**
 * @author 212042764
 * 
 */
public class TelnetCommand {
	private String hostname = null;
	private TelnetClient telnetClient = null;
	private InputStream in = null;
	private PrintStream out = null;
	private String prompt = null;
	private Properties properties = null;

	public TelnetCommand(String modelType) throws FileNotFoundException,
			IOException {
		telnetClient = new TelnetClient();
		String eawMount = ApplicationInfo.getInstance().getProperty(
				PropertyConstants.EAW_II_CHECKOUT_FILE_LOC);
		loadProperties(eawMount + modelType);
		ASCLogger.info(TelnetCommand.class, "init", "Loaded Properties:"
				+ properties);
	}

	/**
	 * Loads the II_checkout.properties file
	 * 
	 * @param fileName
	 * @throws IOException
	 */
	private void loadProperties(String fileName) throws IOException {
		Object content[] = ASCFileHandler.readFile(fileName);
		StringBuffer extractedContent = new StringBuffer();
		for (int iCount = 0; iCount < content.length; iCount++) {
			String line = (String) content[iCount];
			if (!ASCUtil.isNullOrEmpty(line)) {
				if (!line.startsWith(":#")) {
					if (line.startsWith(":")) {
						line = line.substring(1);
					}
					if (line.indexOf("=") != -1) {
						extractedContent.append(line).append("\n");
					}
				}
			}
		}
		InputStream inputStream = null;
		try {
			inputStream = new ByteArrayInputStream(extractedContent.toString()
					.getBytes());
			properties = new Properties();
			properties.clear();
			properties.load(inputStream);
		} finally {
			ASCIOHandler.closeInputStream(inputStream);
		}
	}

	/**
	 * Connects to the telnet port on the device
	 * 
	 * @param hostname
	 * @param username
	 * @param password
	 * @param timeoutMillis
	 * @throws TelnetCommandException
	 */
	public void connect(String hostname, String username, String password,
			int timeoutMillis) throws TelnetCommandException {
		this.hostname = hostname;
		try {
			telnetClient.setDefaultTimeout(timeoutMillis);
			telnetClient.connect(hostname);
			telnetClient.setSoTimeout(timeoutMillis);
			in = telnetClient.getInputStream();
			out = new PrintStream(telnetClient.getOutputStream());
			readUntil(properties.getProperty("LoginUserPrompt"));
			write(username);
			readUntil(properties.getProperty("LoginPasswordPrompt"));
			write(password);
			readUntil(prompt);
		} catch (SocketException socketException) {
			throw new TelnetCommandException("Failed to connect to hostname:"
					+ hostname, socketException);
		} catch (IOException ioException) {
			throw new TelnetCommandException("Failed to connect to hostname:"
					+ hostname, ioException);
		}
	}

	/**
	 * Sets insite prompt
	 */
	public void setInsitePrompt() {
		prompt = properties.getProperty("InsitePrompt");
	}

	/**
	 * Sets root prompt
	 */
	public void setRootPrompt() {
		prompt = properties.getProperty("RootPrompt");
	}

	/**
	 * Writes to output stream
	 * 
	 * @param value
	 */
	private void write(String value) {
		out.println(value);
		out.flush();
	}

	/**
	 * Read until the pattern is found
	 * 
	 * @param pattern
	 * @return
	 * @throws IOException
	 */
	private String readUntil(String pattern) throws IOException {
		char lastChar = pattern.charAt(pattern.length() - 1);
		StringBuffer sb = new StringBuffer();
		char ch = (char) in.read();
		while (true) {
			sb.append(ch);
			if (ch == lastChar) {
				if (sb.toString().endsWith(pattern)) {
					return sb.toString();
				}
			}
			ch = (char) in.read();
		}
	}

	/**
	 * Executes command and returns results
	 * 
	 * @param command
	 * @return
	 * @throws TelnetCommandException
	 */
	public String executeCommand(String command) throws TelnetCommandException {
		write(command);
		try {
			return readUntil(prompt + "");
		} catch (IOException ioException) {
			throw new TelnetCommandException("Failed to execute command:"
					+ command, ioException);
		}
	}

	/**
	 * Resets socket timeout to passed value
	 * 
	 * @param timeoutMillis
	 * @throws TelnetCommandException
	 */
	public void setTimeout(int timeoutMillis) throws TelnetCommandException {
		try {
			telnetClient.setSoTimeout(timeoutMillis);
		} catch (SocketException socketException) {
			throw new TelnetCommandException("Failed to set timeout to:"
					+ timeoutMillis, socketException);
		}
	}

	/**
	 * Disconnects telnet client
	 */
	public void disconnect() {
		if (telnetClient.isConnected()) {
			try {
				telnetClient.disconnect();
			} catch (IOException e) {
				ASCLogger.info("Failed to disconnect from host:" + hostname);
			}
		}
	}

	/**
	 * @return the outputStream
	 */
	public OutputStream getOutputStream() {
		return telnetClient.getOutputStream();
	}

	/**
	 * @return the inputStream
	 */
	public InputStream getInputStream() {
		return telnetClient.getInputStream();
	}
}
